// PAR.cpp : main project file.

#include "UPO_solver.h"
#include "mpi.h"
#include <sstream>



using namespace std;
#define LENGTH 500


#define ALL_OUTPUTS_OFF 0


int main(int argc, char *argv[])
{	
	char *inFile;
	int my_rank;
	int p;
	//int message[LENGTH];
	//MPI_Status status;
	InputData* input;
	UPO_solver* solver;

	int ClosingTag = 2;
	int InputDataTag = 1;
	
	int total_nodes = 0;
	int total_edges = 0;
	int position = 0;
	//int ret;



	/* start up MPI */
	MPI_Init( &argc, &argv );

	/* find out process rank */
	MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

	/* find out number of processes */
	MPI_Comm_size(MPI_COMM_WORLD, &p);

	if (my_rank == 0) 
	{

#if ALL_OUTPUTS_OFF 
		cout << "Greetings from process " << my_rank << 
			"! I am starting to load data." << endl;
#endif

		if (argc < 2) 
		{
			cout << "Usage: " << argv[0] << " input_file" << endl;
			return 1;
		}
		else 
		{
			inFile = argv[1];
		}

		input = new InputData(inFile);
		/* It's necessary to check whether is input ready */
		if (! input->inputReady())
			return 1;
		
#if ALL_OUTPUTS_OFF 
		cout << "Starting to send data: " << endl;
#endif
		total_nodes = input->getMatrixDimension();
		total_edges = input->getEdgesNumber();

		input->Serialize();
				
		/*
		for (int i = 0; i < input->getMatrixDimension() * input->getMatrixDimension(); i++)
			cout << input->linmatrix[i];
			
		cout << endl;
		input->printMatrix();
		*/
		
		MPI_Bcast (&total_nodes, 1, MPI_INT, 0, MPI_COMM_WORLD);
		MPI_Bcast (&total_edges, 1, MPI_INT, 0, MPI_COMM_WORLD);
		
		MPI_Bcast (input->linmatrix, total_nodes * total_nodes, 
			MPI_INT, 0, MPI_COMM_WORLD);						
	

		input->deleteLinmatrix();
		MPI_Barrier (MPI_COMM_WORLD);

		double t1 = MPI_Wtime(); /* pocatecni cas */
		//cout << my_rank << "left barrier" << endl;
		
		
		solver = new UPO_solver(input);
		//cerr << "OK\n";
		solver->SetRank(my_rank);
		
		solver->SplitWork();
		// Temporary divide 
		//solver->DivideJob();
		solver->Solve();

		MPI_Barrier (MPI_COMM_WORLD);

		double t2 = MPI_Wtime(); /* koncovy cas */

		cout << "Computation time was " << t2-t1 << endl;

		solver->PrintStats();

		delete solver;
		delete input;

	}
	else
	{
#if ALL_OUTPUTS_OFF 
		cout << "I am process " << my_rank << endl;
#endif
		
		MPI_Bcast (&total_nodes, 1, MPI_INT, 0, MPI_COMM_WORLD);
		MPI_Bcast (&total_edges, 1, MPI_INT, 0, MPI_COMM_WORLD);
		
		//cout << my_rank << ":" << total_nodes << " " << total_edges << endl;

		
		input = new InputData(total_nodes, total_edges);
		
		MPI_Bcast (input->linmatrix, total_nodes * total_nodes, 
				MPI_INT, 0, MPI_COMM_WORLD);
						
		//cout << my_rank << "left barrier" << endl;
		
		
		/*
		for (int i = 0; i < total_nodes * total_nodes; i++)
			cout << input->linmatrix[i];
		cout << endl;
		*/
		
		
		if (input->Deserialize() == false) {
			cout << "Error Deserialize" << endl;
			return 1;
		}
		
		MPI_Barrier (MPI_COMM_WORLD);
		
		//input->printMatrix();
		
		solver = new UPO_solver(input);
		solver->SetRank(my_rank);
		
		// Temporary divide 
		//solver->DivideJob();
		solver->Solve();

		MPI_Barrier (MPI_COMM_WORLD);


		solver->PrintStats();

		delete solver;
		delete input;

	}

	MPI_Barrier (MPI_COMM_WORLD);


	/* shut down MPI */
	MPI_Finalize();

#if ALL_OUTPUTS_OFF 
	cout << "Process " << my_rank << ": Closed!!!!" << endl; 
#endif

	return 0;
}
